package chapter_06


class Rational(n: Int, d: Int) extends Ordered[Rational] {
  // 混入特质Ordered

  // reuqire方法带有一个布尔型参数。如果为假抛出异常。
  require(d != 0)
  private val g = gcd(n.abs, d.abs)
  val numer: Int = n / g
  val denom: Int = d / g

  // 辅助构造器
  /*
   * scala里每个构造器的调用将结束语对主构造器的调用，因此主构造器是类的唯一入口点。scala里面只有主构造器才能调用超累的构造器，
   * 这点和java不一样，java要么调用同类的其他构造器，要么直接调用超类的构造器。
   */
  def this(n: Int) = this(n, 1)

  override def toString = numer + "/" + denom

  def add(that: Rational): Rational =
    // new Rational(n * that.d + that.n * d, d * that.d)
    /*
     * 尽管类参数n和d都在add代码可引用的范围内，但是add方法仅访问调用对象自身的值。因此，当add实现访问n或d的时候，编译器能够提
     * 供给你这些参数值。但that的n和d绝对无法访问，因为that并不是调用add的Rational对象。
     */
    new Rational(
      numer * that.denom + that.numer * denom,
      denom * that.denom
    )

  def lessThan(that: Rational) =
    // 可以省略this
    this.numer * that.denom < that.numer * this.denom

  def max(that: Rational) =
    // 第一个this.lessThan的this可以省略，但是第二个不能
    if (this.lessThan(that)) that else this

  private def gcd(a: Int, b: Int): Int =
     if (b == 0) a else gcd(b, a % b)

  def +(that: Rational): Rational =
    // 定义操作符方法
    new Rational(
      numer * that.denom + that.numer * denom,
      denom * that.denom
    )

  def +(i: Int): Rational =
    new Rational(numer + i * denom, denom)

  def -(that: Rational): Rational =
    new Rational(
      numer * that.denom - that.numer * denom,
      denom * that.denom
    )

  def -(i: Int): Rational =
    new Rational(numer - i * denom, denom)

  def *(that: Rational): Rational =
    new Rational(numer * that.numer, denom * that.denom)

  def *(i: Int): Rational =
    new Rational(numer * i, denom)

  def /(that: Rational): Rational =
    new Rational(numer * that.denom, denom * that.numer)

  def /(i: Int): Rational =
    new Rational(numer, denom * i)

  // 第十二章 混入特质Ordered
  def compare(that: Rational) =
    (this.numer * that.denom) - (that.numer * this.denom)
}


object Rational {

  def main(args: Array[String]): Unit = {
    val a = new Rational(1, 2)
    val b = new Rational(2, 3)
    println(a + b)

    val r: Rational = new Rational(2)

    // 隐式转换
    implicit def intToRational(x: Int) = new Rational(x)
    println(2 * r)

    // 第十二章
    println(a >= b)
    println(a < b)
  }
}


